package com.deanlib.cabinet.service;

import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.media.MediaMetadataRetriever;
import android.net.Uri;
import android.os.Build;
import android.provider.MediaStore;
import android.text.TextUtils;

import androidx.annotation.RequiresApi;

import com.arthenica.ffmpegkit.FFmpegKit;
import com.arthenica.ffmpegkit.FFmpegSession;
import com.arthenica.ffmpegkit.ReturnCode;
import com.deanlib.cabinet.R;
import com.deanlib.cabinet.app.Constants;
import com.deanlib.cabinet.base.BaseService;
import com.deanlib.cabinet.data.AppDatabase;
import com.deanlib.cabinet.data.db.ResourceDao;
import com.deanlib.cabinet.data.event.MessageEvent;
import com.deanlib.cabinet.data.event.ResourceChangeEvent;
import com.deanlib.cabinet.data.model.Resource;
import com.deanlib.cabinet.data.network.schedulers.SchedulerProvider;
import com.deanlib.cabinet.utils.ConfigManager;
import com.deanlib.cabinet.utils.FileUtilsExt;
import com.deanlib.cabinet.utils.MediaUtilsExt;
import com.deanlib.plantern.utils.MD5Utils;
import com.elvishew.xlog.XLog;

import org.greenrobot.eventbus.EventBus;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import io.reactivex.Observable;
import io.reactivex.ObservableOnSubscribe;

/**
 * 提供本地资源的查询，入库
 *
 * @Created by Dean
 * @Date 2023/6/6
 */
public class ResourceCollectService extends BaseService {

    @Override
    public void onCreate() {
        super.onCreate();
//        EventBus.getDefault().register(this);
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        saveLocalResourceToDB();
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
//        EventBus.getDefault().unregister(this);
    }

    @Override
    public int getNotifyId() {
        return Constants.SERVICE_NOTIFY_ID_RESOURCE_COLLECT;
    }

    /**
     * 获取本地数据存入数据库
     *
     * @return
     */
    private void saveLocalResourceToDB() {
        addDisposable(Observable.create((ObservableOnSubscribe<Boolean>) emitter -> {
            long l = System.currentTimeMillis();
            XLog.d("saveLocalResourceToDB start");
            Context context = getApplicationContext();
            int newItemCount = 0;
            if (context != null) {

                List<Resource> resources = new ArrayList<>();
                //获取图片
                resources.addAll(getLocalMediaData(context, MediaStore.Images.Media.EXTERNAL_CONTENT_URI));
                //获取视频
                resources.addAll(getLocalMediaData(context, MediaStore.Video.Media.EXTERNAL_CONTENT_URI));
                //数据库记录所有数据，并且数据库存储去重

                if (!resources.isEmpty()) {
                    int resourceSize = resources.size();
                    for (int i = 0; i < resources.size(); i++) {
                        Resource resource = resources.get(i);
                        if (!TextUtils.isEmpty(resource.localPath)) {
                            //从本地查询到的数据
                            String message = getString(R.string.collect_local_resource, resourceSize, i + 1, newItemCount);
                            EventBus.getDefault().post(new MessageEvent(MessageEvent.TYPE_MESSAGE, message));//todo
                            Resource dbResource = AppDatabase.getDaoSession().getResourceDao().queryBuilder()
                                    .where(ResourceDao.Properties.LocalPath.eq(resource.localPath)).unique();
                            if (dbResource == null) {
                                //新增数据
                                //先算出md5
                                //计算MD5 数据量大时会非常慢 todo
                                try {
                                    String md5Value = MD5Utils.md5(new File(resource.localPath));
                                    if (!TextUtils.isEmpty(md5Value)) {
                                        resource.md5 = md5Value;
                                        resource.newMd5 = md5Value;
                                    }
                                    AppDatabase.getDaoSession().getResourceDao().insert(resource);
                                    newItemCount++;
                                } catch (IOException e) {
                                    e.printStackTrace();
                                }
                            } else {
                                //md5是主键，所以如果查到了，md5必然存在
                                //更新数据
                                //更新部分字段
                                boolean changed = false;
                                if (TextUtils.isEmpty(dbResource.path) && !TextUtils.isEmpty(resource.path)) {
                                    dbResource.path = resource.path;
                                    changed = true;
                                }
                                if (TextUtils.isEmpty(dbResource.title) && !TextUtils.isEmpty(resource.title)) {
                                    dbResource.title = resource.title;
                                    changed = true;
                                }
                                if (dbResource.dateModified == null && resource.dateModified != null) {
                                    dbResource.dateModified = resource.dateModified;
                                    changed = true;
                                }
                                if (TextUtils.isEmpty(dbResource.localPath) && !TextUtils.isEmpty(resource.localPath)) {
                                    dbResource.localPath = resource.localPath;
                                    changed = true;
                                }
                                if (changed) {
                                    AppDatabase.getDaoSession().getResourceDao().update(dbResource);
                                }

                            }
                        } else {
                            //无效的数据
                        }
                    }
                }
                XLog.d("saveLocalResourceToDB end 用时：" + (System.currentTimeMillis() - l) + "ms, 得到资源：" + resources.size() + "个");
            }

            emitter.onNext(newItemCount > 0);
            emitter.onComplete();
        }).compose(SchedulerProvider.getInstance().applySchedulers()).subscribe(b -> {
            if (b) {
                EventBus.getDefault().postSticky(new ResourceChangeEvent());
            }
        }));
    }

    /**
     * 从内容提供者获取本地媒体数据
     *
     * @param context
     * @param queryUri
     * @return
     */
    private List<Resource> getLocalMediaData(Context context, Uri queryUri) {
        List<Resource> list = new ArrayList<>();
//        String order = MediaStore.MediaColumns.DATE_ADDED + " DESC ";
//        Cursor cursor = context.getContentResolver().query
//                (queryUri, null, MediaStore.MediaColumns.DATE_ADDED + ">? and "
//                        + MediaStore.MediaColumns.DATE_ADDED + "<?",
//                        new String[]{String.valueOf(date1/1000), String.valueOf(date2/1000)}, null);
        Cursor cursor = context.getContentResolver().query
                (queryUri, new String[]{
                        MediaStore.MediaColumns.DATA,
                        MediaStore.MediaColumns._ID,
                        MediaStore.MediaColumns.DATE_ADDED,
                        MediaStore.MediaColumns.DATE_MODIFIED,
                        MediaStore.MediaColumns.TITLE,
                        MediaStore.MediaColumns.BITRATE,
//                        MediaStore.Video.VideoColumns.CAPTURE_FRAMERATE, //总是获取到null
                        MediaStore.MediaColumns.WIDTH,
                        MediaStore.MediaColumns.HEIGHT,
                        MediaStore.MediaColumns.SIZE,
                        MediaStore.Images.ImageColumns.LONGITUDE,
                        MediaStore.Images.ImageColumns.LATITUDE,
                        MediaStore.MediaColumns.DURATION,
                        MediaStore.Video.Thumbnails.DATA,
                        MediaStore.MediaColumns.MIME_TYPE,
                }, null, null, null);
        if (cursor != null) {
            while (cursor.moveToNext()) {
                String path = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATA));
                boolean needSyncFile = false;
                for (String dirPath : ConfigManager.getInstance().getSyncDirList()) {
                    if (path.startsWith(dirPath)) {
                        needSyncFile = true;
                        break;
                    }
                }
                if (needSyncFile) {

                    long id = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.MediaColumns._ID));
                    long dateAdded = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATE_ADDED));
                    long dateModified = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATE_MODIFIED));
                    String title = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.TITLE));
//                            String relativePath = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.RELATIVE_PATH));

                    int width = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.WIDTH));
                    int height = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.HEIGHT));
                    long size = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.SIZE));
                    double longitude = cursor.getDouble(cursor.getColumnIndexOrThrow(MediaStore.Images.ImageColumns.LONGITUDE));
                    double latitude = cursor.getDouble(cursor.getColumnIndexOrThrow(MediaStore.Images.ImageColumns.LATITUDE));
                    String thumbnail = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Video.Thumbnails.DATA));

                    long duration = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DURATION));
                    long bitrate = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.BITRATE));
//                    int frame = cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Video.VideoColumns.CAPTURE_FRAMERATE));

//                Uri uri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, id);
//                String path = FileUtils.getPath(uri);

                    String mineType = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.MIME_TYPE));
//                if (duration>0) {
//                    Bitmap bitmap = ThumbnailUtils.extractThumbnail(
//                            ThumbnailUtils.createVideoThumbnail(path, kind),
//                            width/2, height/2, ThumbnailUtils.OPTIONS_RECYCLE_INPUT);
//                }
                    int frameRate = 0;
//                    long duration = 0;
//                    long bitrate = 0;
                    if(FileUtilsExt.isVideo(mineType)){
                        MediaMetadataRetriever retriever = new MediaMetadataRetriever();
                        retriever.setDataSource(path);
                        String frameCount = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_FRAME_COUNT);
                        long count = Long.parseLong(frameCount);
                        //计算帧率
                        long dt = duration/count; // 平均每帧的时间间隔
                        frameRate = (int) (1000/dt); // 帧率

//                        StringBuilder cmd = new StringBuilder();
//                        cmd.append("-i ").append(task1.getPath());
//                        for (Map.Entry<String, String> option : compressOptions.entrySet()) {
//                            cmd.append(" ").append(option.getKey()).append(" ").append(option.getValue());
//                        }
//                        cmd.append(" ").append(tempPath);
//                        XLog.i("OssManager WorkThread ffmpeg cmd:" + cmd);
//                        FFmpegSession ffmpegSession = FFmpegKit.execute(cmd.toString());
//                        XLog.i("OssManager WorkThread 压缩结果：" + ffmpegSession.getReturnCode().getValue());
//                        int ffmpegReturnCode = ffmpegSession.getReturnCode().getValue();
//                        if (ffmpegReturnCode == ReturnCode.SUCCESS) {
//                            XLog.i("OssManager WorkThread 压缩成功");
//                            upload(task1);
//                        } else {
//                            XLog.i("OssManager WorkThread 压缩失败 code: " + ffmpegReturnCode);
//                            task1.setResultError("Compress Fail, FFmpeg Return Code:" + ffmpegReturnCode);
//                        }
                    }


                    Resource resource = new Resource();
                    resource.title = title;
                    resource.resCreateTime = dateAdded;
                    resource.dateModified = dateModified;
                    resource.bitrate = bitrate;
                    resource.frameRate = frameRate;
                    resource.duration = duration / 1000;
                    resource.width = width;
                    resource.height = height;
                    resource.size = size;
                    resource.longitude = longitude;
                    resource.latitude = latitude;
                    resource.localPath = path;
                    resource.localThumbnail = thumbnail;
                    resource.mineType = mineType;

                    list.add(resource);
                }
            }
            cursor.close();
        }
        return list;
    }
}
